﻿using System;

namespace Dynamic.DataStructures
{
    
    /// <summary>
    /// Represents a first-in, first-out collection of objects.
    /// </summary>
    /// <typeparam name="T">Specifies the type of elements in the queue.</typeparam>
    public class Queue<T> : IQueue<T>
    {

        private int count;
        
        /// <summary>
        /// Gets the number of elements contained in the Queue.
        /// </summary>
        public int Count 
        {
            get { return count; }
        }

        /// <summary>
        /// Node to the first element in the Queue.
        /// </summary>
        Node<T> Head { get; set; }

        /// <summary>
        /// Node to the last element in the Queue.
        /// </summary>
        Node<T> Tail { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Queue" /> class that is empty.
        /// </summary>
        public Queue()
        {
            Head = Tail = null;
            count = 0;
        }

        /// <summary>
        /// Adds and elment to the end of the Queue.
        /// </summary>
        /// <param name="item">The object to add to the Queue.</param>
        public void Enqueue(T item)
        {
            Node<T> node = new Node<T>();
            node.Information = item;
            node.Next = null;
            if (Head == null)
            {
                Head = Tail = node;
            }
            else
            {
                Tail.Next = node;
                Tail = node;
            }

            count++;   
        }

        /// <summary>
        /// Removes and returns the object at the beginning of the Queue.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">Thrown when the Queue is empty.</exception>
        /// <returns>The first element of the Queue.</returns>
        public T Dequeue()
        {
            if (Head == null)
            {
                throw new InvalidOperationException("The Queue is empty");
            }

            T information = Head.Information;
            
            Head = Head.Next;
            count--;
            
            return information;            
        }

        /// <summary>
        /// Returns the object at the beginning of the Queue without removing it.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">Thrown when the Queue is empty.</exception>
        /// <returns>The first element of the Queue.</returns>
        public T Peek()
        {
            if (Head == null)
            {
                throw new InvalidOperationException("The Queue is empty");
            }

            return Head.Information;
        }
    }
}
